#include <fstream>
#include <algorithm>
#include <vector>
#include <map>
#include <sstream>
#include "BreakerMap.h"

BreakerMap::BreakerMap()
{
}

BreakerMap::~BreakerMap()
{
}

static void WriteBloc(std::ofstream& _ofs, std::map<std::string, int>& _ids, Bloc* _b)
{
	if (_b != NULL)
	{
		std::map<std::string, int>::iterator it = _ids.find(_b->GetType());
		if (it != _ids.end())
		{
			_ofs << it->second;
			_ofs << " ";
		}
	}
	else
		_ofs << ". ";
}

static void WriteMap(std::ofstream& _ofs, std::map<std::string, int>& _ids,
					 BlocManager& _blocManager)
{
	_ofs << "#MAP" << std::endl;
	int w = 800 / 32, h = 560 / 16;
	for (Sint16 y = 0; y < h; y++)
	{
		for (Sint16 x = 0; x < w; x++)
			WriteBloc(_ofs, _ids, _blocManager.GetAt(x * 32, y * 16));
		_ofs << std::endl;
	}
}

static void WriteIds(std::ofstream& _ofs, std::map<std::string, int>& _ids,
					 BlocManager& _blocManager)
{
	std::vector<Bloc*> blocs;
	_blocManager.GetOriginals(blocs);
	int max = blocs.size();
	_ofs << "#IDS" << std::endl;
	for (int i = 0; i < max; i++)
	{
		_ofs << i;
		_ofs << "=" << blocs[i]->GetType() << std::endl;
		_ids[blocs[i]->GetType()] = i;
	}
}

bool BreakerMap::Save(std::string const& _background,
					  std::wstring const& _path, BlocManager& _blocManager)
{
	std::ofstream ofs(_path.c_str(), std::ios_base::out | std::ios_base::trunc);

	if (ofs.fail())
		return (false);
	
	ofs << "background=" << _background << std::endl;
	std::map<std::string, int> ids;
	WriteIds(ofs, ids, _blocManager);
	WriteMap(ofs, ids, _blocManager);

	ofs.close();
	return (true);
}

static void ReadId(std::map<int, std::string>& _ids,
				   BlocManager& _blocManager, std::string& _sLine)
{
	int b = _sLine.find('=', 0);
	std::string first = _sLine.substr(0, b);
	int notSpace = _sLine.find_first_not_of(" \t", b + 1);
	std::string last = _sLine.substr(notSpace);
	int id = 0;
	std::istringstream iss(first);
	iss >> id;
	_ids[id] = last;
	if (_blocManager.Find(last) == NULL)
		_blocManager.AddOriginal(last);
}

static void ReadBloc(std::map<int, std::string>& _ids, BlocManager& _blocManager,
					 std::string& _sLine, int& _x, int& _y)
{
	
	int offset = 0;
	for (int i = 0; i < _sLine.size(); i++)
	{
		int newOffset = _sLine.find(' ', offset);
		int noSpace = _sLine.find_first_not_of(" \t", newOffset + 1);
		std::string s = _sLine.substr(offset, newOffset - offset);
		//_sLine = _sLine.substr(newOffset + 1);
		if (noSpace > 0)
			offset = noSpace;
		else
			offset = newOffset + 1;
		if (s == ".")
		{
			_x++;
			continue ;
		}
				
		int id = 0;
		std::istringstream iss(s);
		iss >> id;

		std::map<int, std::string>::iterator it = _ids.find(id);
		if (it != _ids.end())
		{
			Bloc const* b = _blocManager.Find(it->second);
			if (b != NULL)
				_blocManager.Add(b->GetType(), SDL::UTILS::Rect(_x * 32, _y * 16));
		}
		_x++;
	}
	_y++;
	_x = 0;
}

static void ParseLine(std::string* _background,
					  std::map<int, std::string>& _ids, BlocManager& _blocManager,
					  std::string& _sLine, int& _x, int& _y,
					  bool& _idMode, bool& _mapMode)
{
	if (_sLine == "#IDS")
	{
		_idMode = true;
		return ;
	}
	if (_sLine == "#MAP")
	{
		_idMode = false;
		_mapMode = true;
		return ;
	}
	if (_sLine.find("background") != std::string::npos)
	{
		int b = _sLine.find('=', 0);
		std::string first = _sLine.substr(0, b);
		int notSpace = _sLine.find_first_not_of(" \t", b + 1);
		*_background = _sLine.substr(notSpace);
	}
	if (_idMode == true)
		ReadId(_ids, _blocManager, _sLine);
	else if (_mapMode == true)
		ReadBloc(_ids, _blocManager, _sLine, _x, _y);

}

bool BreakerMap::Load(std::string* _background,
					  std::wstring const& _path, BlocManager& _blocManager)
{
	std::ifstream ifs(_path.c_str(), std::ios_base::in);

	if (ifs.fail())
		return (false);

	_blocManager.Clear();
	//_blocManager.ClearOriginals();

	int max = 42000;
	char line[42000];
	std::map<int, std::string> ids;
	bool idMode = false, mapMode = false;
	int x = 0, y = 0;
	while (ifs.getline(line, max))
	{
		std::string sLine(line);
		ParseLine(_background, ids, _blocManager, sLine, x, y, idMode, mapMode);
	}

	ifs.close();

	return (true);
}
